<template>
  <div class="image-page">
    <el-row :gutter="20">
      <el-col :lg="10" :md="11" :sm="24" :xs="24">
        <el-card class="upload-card" shadow="hover">
          <template #header>
            <div class="card-header">
              <div class="card-heading">
                <el-icon class="heading-icon"><PictureRounded /></el-icon>
                <div>
                  <h3>智能影像分析</h3>
                  <p>上传舌象或伤口图片，获取 AI 模拟诊断</p>
                </div>
              </div>
              <el-tag type="success" effect="plain">Mock</el-tag>
            </div>
          </template>
          <el-form label-position="top">
            <el-form-item label="分析类型">
              <el-segmented v-model="analysisType" :options="analysisOptions" size="large" class="type-segment" />
            </el-form-item>
            <el-form-item label="图片上传">
              <el-upload
                ref="uploadRef"
                class="upload-box"
                :auto-upload="false"
                :limit="1"
                :file-list="fileList"
                accept="image/*"
                drag
                :on-remove="handleRemove"
                :on-change="handleChange"
              >
                <el-icon class="upload-icon"><UploadFilled /></el-icon>
                <div class="el-upload__text">
                  将图片拖拽至此，或 <em>点击上传</em>
                </div>
                <div class="el-upload__tip">支持 jpg/png/jpeg，单张不超过 8MB</div>
              </el-upload>
            </el-form-item>
            <div v-if="previewUrl" class="preview-box">
              <img :src="previewUrl" alt="预览图片" />
            </div>
            <div class="form-actions">
              <el-button type="primary" :loading="uploading" :disabled="!selectedFile" @click="handleSubmit">
                <el-icon class="submit-icon"><MagicStick /></el-icon>
                开始分析
              </el-button>
              <el-button link type="info" @click="resetUpload(true)" :disabled="uploading">重置</el-button>
            </div>
          </el-form>
          <el-alert
            type="info"
            title="温馨提示"
            :closable="false"
            show-icon
            description="示例环境仍使用模拟分析结果，后续将对接真实影像识别模型，请勿上传敏感隐私图片。"
          />
        </el-card>
      </el-col>
      <el-col :lg="14" :md="13" :sm="24" :xs="24">
        <el-card class="history-card" shadow="hover">
          <template #header>
            <div class="history-header">
              <h3>分析记录</h3>
              <el-select v-model="filters.analysisType" placeholder="全部类型" clearable size="small" @change="loadRecords">
                <el-option label="全部类型" :value="undefined" />
                <el-option v-for="option in analysisOptions" :key="option.value" :label="option.label" :value="option.value" />
              </el-select>
            </div>
          </template>
          <el-empty v-if="!listLoading && records.length === 0" description="暂无分析记录，快来体验 AI 影像分析吧" />
          <el-skeleton v-else :loading="listLoading" animated :rows="6">
            <el-timeline class="history-timeline">
              <el-timeline-item
                v-for="item in records"
                :key="item.id"
                :timestamp="formatTime(item.createdAt)"
                placement="top"
              >
                <el-card shadow="never" class="timeline-card">
                  <div class="timeline-header">
                    <el-tag :type="tagType(item.analysisType)" effect="dark" size="small">
                      {{ analysisLabel(item.analysisType) }}
                    </el-tag>
                    <span class="confidence">置信度：{{ formatConfidence(item.confidence) }}</span>
                  </div>
                  <div class="diagnosis-block">
                    <p class="label">AI 诊断</p>
                    <p class="content">{{ item.diagnosis }}</p>
                  </div>
                  <div class="suggestion-block">
                    <p class="label">调理建议</p>
                    <ul>
                      <li v-for="suggestion in item.suggestions" :key="suggestion">{{ suggestion }}</li>
                    </ul>
                  </div>
                  <div class="timeline-actions">
                    <el-button link type="primary" @click="previewRecord(item)">
                      <el-icon><View /></el-icon>
                      查看原图
                    </el-button>
                  </div>
                </el-card>
              </el-timeline-item>
            </el-timeline>
          </el-skeleton>
        </el-card>
      </el-col>
    </el-row>

    <el-dialog v-model="previewDialog.visible" title="原图预览" width="720px" destroy-on-close>
      <div class="dialog-body">
        <img v-if="previewDialog.imageUrl" :src="previewDialog.imageUrl" alt="分析图片" />
        <el-empty v-else description="图片载入中..." />
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="previewDialog.visible = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import dayjs from 'dayjs';
import type { UploadFile, UploadFiles, UploadInstance, UploadRawFile } from 'element-plus';
import { ElMessage } from 'element-plus';
import { MagicStick, PictureRounded, UploadFilled, View } from '@element-plus/icons-vue';
import { uploadImage, fetchImageRecords, getImagePreview } from '@/api/images';
import type { ImageRecord, ImageAnalysisType } from '@/types/image';

const uploadRef = ref<UploadInstance>();
const fileList = ref<UploadFile[]>([]);
const selectedFile = ref<UploadRawFile | null>(null);
const previewUrl = ref<string>('');
const uploading = ref(false);
const listLoading = ref(false);

const analysisType = ref<ImageAnalysisType>('TONGUE_DIAGNOSIS');

const analysisOptions = [
  { label: '舌诊分析', value: 'TONGUE_DIAGNOSIS' as ImageAnalysisType },
  { label: '创口识别', value: 'WOUND_ASSESSMENT' as ImageAnalysisType },
  { label: '皮肤评估', value: 'SKIN_CONDITION' as ImageAnalysisType },
];

const filters = reactive<{ analysisType?: ImageAnalysisType }>({ analysisType: undefined });

const records = ref<ImageRecord[]>([]);

const analysisLabel = (value: ImageAnalysisType) => analysisOptions.find((option) => option.value === value)?.label ?? value;

const tagType = (value: ImageAnalysisType) => {
  switch (value) {
    case 'TONGUE_DIAGNOSIS':
      return 'success';
    case 'WOUND_ASSESSMENT':
      return 'danger';
    case 'SKIN_CONDITION':
    default:
      return 'warning';
  }
};

const formatConfidence = (value: number) => `${(value * 100).toFixed(0)}%`;

const formatTime = (time: string) => dayjs(time).format('YYYY/MM/DD HH:mm');

const revokePreviewUrl = () => {
  if (previewUrl.value) {
    URL.revokeObjectURL(previewUrl.value);
    previewUrl.value = '';
  }
};

const handleChange = (file: UploadFile, files: UploadFiles) => {
  const raw = file.raw as UploadRawFile | undefined;
  if (!raw) {
    ElMessage.error('文件读取失败，请重试');
    resetUpload(true);
    return;
  }

  if (!raw.type.startsWith('image/')) {
    ElMessage.error('仅支持上传图片文件');
    resetUpload(true);
    return;
  }

  const isLt8M = raw.size / 1024 / 1024 < 8;
  if (!isLt8M) {
    ElMessage.error('图片大小需小于 8MB');
    resetUpload(true);
    return;
  }

  revokePreviewUrl();
  selectedFile.value = raw;
  previewUrl.value = URL.createObjectURL(raw);
  fileList.value = files.slice(-1);
};

const handleRemove = () => {
  resetUpload();
};

const resetUpload = (clearComponent = false, revokeUrl = true) => {
  selectedFile.value = null;
  if (revokeUrl) {
    revokePreviewUrl();
  } else {
    previewUrl.value = '';
  }
  fileList.value = [];
  if (clearComponent) {
    uploadRef.value?.clearFiles();
  }
};

const handleSubmit = async () => {
  if (!selectedFile.value) {
    ElMessage.warning('请先选择需要分析的图片');
    return;
  }
  uploading.value = true;
  try {
    const formData = new FormData();
    formData.append('file', selectedFile.value);
    formData.append('analysisType', analysisType.value);
    const data = await uploadImage(formData);
    const localPreviewUrl = previewUrl.value;
    records.value = [data, ...records.value].slice(0, 50);
    ElMessage.success('分析完成');
    previewRecord(data, localPreviewUrl);
    resetUpload(true, false);
  } finally {
    uploading.value = false;
  }
};

const loadRecords = async () => {
  listLoading.value = true;
  try {
    records.value = await fetchImageRecords({ analysisType: filters.analysisType, page: 1, size: 20 });
  } finally {
    listLoading.value = false;
  }
};

const previewDialog = reactive<{ visible: boolean; imageUrl: string }>({
  visible: false,
  imageUrl: '',
});

const previewRecord = async (record: ImageRecord, localUrl?: string | null) => {
  previewDialog.visible = true;
  if (localUrl) {
    previewDialog.imageUrl = localUrl;
    return;
  }
  try {
    const response = await getImagePreview(record.id);
    const blob = new Blob([response], { type: record.contentType || 'image/jpeg' });
    previewDialog.imageUrl = URL.createObjectURL(blob);
  } catch (error) {
    ElMessage.error('图片加载失败，请稍后重试');
    previewDialog.visible = false;
  }
};

onMounted(loadRecords);
onBeforeUnmount(() => {
  revokePreviewUrl();
});
</script>

<style scoped lang="scss">
.image-page {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.upload-card,
.history-card {
  border-radius: 16px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.card-heading {
  display: flex;
  align-items: center;
  gap: 1rem;

  h3 {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 600;
    color: #1f2937;
  }

  p {
    margin: 0.25rem 0 0;
    color: #6b7280;
  }
}

.heading-icon {
  font-size: 2.4rem;
  color: #2563eb;
}

.type-segment {
  width: 100%;
}

.upload-box {
  width: 100%;

  :deep(.el-upload-dragger) {
    padding: 1.5rem;
    border-radius: 12px;
  }
}

.upload-icon {
  font-size: 48px;
  color: #3b82f6;
  margin-bottom: 0.5rem;
}

.preview-box {
  margin-bottom: 1rem;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid #e5e7eb;
  background: #f8fafc;

  img {
    width: 100%;
    display: block;
    object-fit: cover;
  }
}

.form-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.submit-icon {
  margin-right: 0.25rem;
}

.history-header {
  display: flex;
  justify-content: space-between;
  align-items: center;

  h3 {
    margin: 0;
    font-size: 1.2rem;
    font-weight: 600;
    color: #1f2937;
  }
}

.history-timeline {
  max-height: 640px;
  overflow-y: auto;
  padding-right: 0.5rem;
}

.timeline-card {
  border-radius: 12px;
  border: 1px solid #e5e7eb;
  background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
}

.timeline-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
}

.confidence {
  color: #1d4ed8;
  font-weight: 500;
}

.diagnosis-block,
.suggestion-block {
  margin-bottom: 0.75rem;

  .label {
    margin: 0 0 0.4rem;
    font-size: 0.85rem;
    color: #64748b;
    letter-spacing: 0.08em;
  }

  .content {
    margin: 0;
    color: #1f2937;
    line-height: 1.6;
  }

  ul {
    margin: 0;
    padding-left: 1.25rem;
    color: #374151;
  }
}

.timeline-actions {
  display: flex;
  justify-content: flex-end;
}

.dialog-body {
  display: flex;
  justify-content: center;
  align-items: center;
  max-height: 70vh;

  img {
    max-width: 100%;
    max-height: 70vh;
    border-radius: 12px;
  }
}

@media screen and (max-width: 768px) {
  .history-timeline {
    max-height: none;
  }
}
</style>

